package com.hzncc.flowable_diboot.custom_field.service.impl;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.diboot.core.binding.Binder;
import com.diboot.core.util.S;
import com.diboot.core.util.SqlExecutor;
import com.diboot.core.vo.LabelValue;
import com.diboot.iam.util.IamSecurityUtils;
import com.hzncc.flowable_diboot.custom_field.entity.CustomTableItemConfig;
import com.hzncc.flowable_diboot.custom_field.entity.FilterSetting;
import com.hzncc.flowable_diboot.custom_field.entity.customfields.TableFieldShowConfig;
import com.hzncc.flowable_diboot.custom_field.entity.customfields.TableFieldShowItem;
import com.hzncc.flowable_diboot.custom_field.exception.CustomTableException;
import com.hzncc.flowable_diboot.custom_field.mapper.customfields.TableFieldShowConfigMapper;
import com.hzncc.flowable_diboot.custom_field.service.CustomTableItemConfigService;
import com.hzncc.flowable_diboot.custom_field.service.FilterSettingService;
import com.hzncc.flowable_diboot.custom_field.vo.CustomTableConfigDetailVO;
import com.hzncc.flowable_diboot.custom_field.vo.CustomTableItemConfigListVO;
import com.hzncc.flowable_diboot.custom_field.vo.FilterSettingListVO;
import com.hzncc.flowable_diboot.custom_field.vo.customfields.TableFieldShowConfigDetailVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.GreaterThan;
import net.sf.jsqlparser.expression.operators.relational.LikeExpression;
import net.sf.jsqlparser.expression.operators.relational.MinorThan;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;

import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SetOperationList;
import org.reflections.Reflections;
import org.reflections.scanners.Scanners;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import com.diboot.core.service.impl.BaseServiceImpl;

import com.hzncc.flowable_diboot.custom_field.entity.CustomTableConfig;

import com.hzncc.flowable_diboot.custom_field.mapper.CustomTableConfigMapper;
import com.hzncc.flowable_diboot.custom_field.service.CustomTableConfigService;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 自定义表格配置 相关Service实现类
 *
 * @author MyName
 * @version 1.0
 * @date 2024-11-14
 * Copyright © MyCorp
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CustomTableConfigServiceImpl extends BaseServiceImpl<CustomTableConfigMapper, CustomTableConfig> implements CustomTableConfigService {

    private final FilterSettingService filterSettingService;
    private final CustomTableItemConfigService customTableItemConfigService;
    private final TableFieldShowConfigMapper tableFieldShowConfigMapper;
    private final Environment env;

    /**
     * 解析sql 获取字段
     *
     * @param sql
     * @return
     */
    @Override
    public List<CustomTableItemConfig> parsingSql(String sql) {
        //sql = sql.replace("<#", "").replace(">", "");
        Select parse = null;
        try {
            parse = (Select) CCJSqlParserUtil.parse(sql);
        } catch (JSQLParserException e) {
            throw new CustomTableException(e);
        }
        PlainSelect plainSelect;
        if (parse instanceof SetOperationList setOperationList) {
            plainSelect = setOperationList.getSelects().get(0).getPlainSelect();
        } else {
            plainSelect = parse.getPlainSelect();
        }
        return plainSelect.getSelectItems().stream().map(selectItem -> new CustomTableItemConfig()
                        .setFieldName(selectItem.getAlias() != null ? selectItem.getAlias().getName()
                                : selectItem.getExpression(Column.class).getColumnName())
                        .setType("TXT_SHORT").setExportable(true).setViewable(true).setWidth("80"))
                .toList();
    }

    /**
     * 解析实体 获取字段
     *
     * @param entity
     * @return
     */
    @Override
    public List<CustomTableItemConfig> parsingEntity(String entity) {
        List<CustomTableItemConfig> list = new ArrayList<>();
        // 通过devtools配置，获取实体类,仅在开发环境有效
        try {
            String model = entity.substring(entity.lastIndexOf(".") + 1);
            String sql = "select id from dbtlc_meta_model where `key` = ? and is_deleted = 0";
            List<Map<String, Object>> maps = SqlExecutor.executeQuery(sql, model);
            if (!maps.isEmpty()) {
                String modelId = (String) maps.get(0).get("id");
                String fieldSql = "select `key`,label,data_type from dbtlc_meta_field where model_id = ? and is_deleted = 0";
                List<Map<String, Object>> fieldMaps = SqlExecutor.executeQuery(fieldSql, modelId);
                for (Map<String, Object> fieldMap : fieldMaps) {
                    list.add(new CustomTableItemConfig()
                            .setFieldLabel((String) fieldMap.get("label"))
                            .setFieldName((String) fieldMap.get("key"))
                            .setType((String) fieldMap.get("data_type"))
                            .setViewable(true)
                            .setExportable(true)
                            .setWidth("80"));
                }
                return list;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 通过反射获取实体类字段
        TableInfo table = null;
        try {
            table = SqlHelper.table(Class.forName(entity));
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(entity + "不存在!");
        }
        if (table != null) {
            String tableName = table.getTableName();
            try {
                List<Map<String, Object>> tableColumns = getTableColumns(tableName);
                tableColumns.forEach(map -> list.add(new CustomTableItemConfig().setType("TXT_SHORT")
                        .setFieldName(convertToHump((String) map.get("columnName")))
                        .setFieldLabel((String) map.get("columnComment"))
                        .setExportable(true)
                        .setViewable(true)));
                return list;
            } catch (Exception e) {
                log.error("获取表格列失败 {}", e.getMessage());
                throw new RuntimeException(e);
            }
//            table.getFieldList().forEach(field -> list.add(new CustomTableItemConfig()
//                    .setFieldName(field.getProperty()).setType("TXT_SHORT").setViewable(true).setExportable(true)));
        }
        return list;
    }

    private String convertToHump(String str) {
        String[] s = str.toLowerCase().split("_");
        StringBuilder humpStr = new StringBuilder(s[0]);
        for (int i = 1; i < s.length; i++) {
            humpStr.append(Character.toUpperCase(s[i].charAt(0))).append(s[i].substring(1));
        }
        return humpStr.toString();
    }

    private List<Map<String, Object>> getTableColumns(String tableName) throws Exception {
        String sql = """
                SELECT COLUMN_NAME as columnName,COLUMN_COMMENT as columnComment,COLUMN_TYPE as columnType from information_schema.columns
                where TABLE_NAME = ? and TABLE_SCHEMA = ?
                """;
        String database = env.getProperty("database");
        if (database == null) {
            database = "diboot_crm";
        }
        List<Map<String, Object>> maps = SqlExecutor.executeQuery(sql, tableName, database);
        return maps;
    }

    /**
     * 获取新增字段
     *
     * @param id
     * @param entity
     * @param sql
     * @return
     */
    @Override
    public List<CustomTableItemConfig> getNewItems(String id, String entity, String sql) {
        List<CustomTableItemConfig> list = null;
        if (entity != null) {
            list = this.parsingEntity(entity);
        } else {
            list = this.parsingSql(sql);
        }
        CustomTableConfigDetailVO viewObject = this.getViewObject(id, CustomTableConfigDetailVO.class);
        List<CustomTableItemConfigListVO> tableItemConfigs = viewObject.getTableItemConfigs();
        // 获取list中新的字段
        if (list != null) {
            return list.stream().filter(e -> tableItemConfigs.stream().noneMatch(item -> item.getFieldName().equals(e.getFieldName()))).toList();
        } else {
            return null;
        }
    }

    /**
     * 获取过滤设置
     *
     * @param sql
     * @return
     */
    @Override
    public List<FilterSetting> getFilterSetting(String sql) {
        //sql = sql.replace("<#", "").replace("#>", "");
        //Select parse = null;
        //try {
        //    parse = (Select) CCJSqlParserUtil.parse(sql);
        //} catch (JSQLParserException e) {
        //    throw new CustomTableException(e);
        //}
        //PlainSelect plainSelect = parse.getPlainSelect();
        //Expression where = plainSelect.getWhere();
        //List<FilterSetting> list = new ArrayList<>();
        //parseExpression(where, list);
        //return list;
        return new ArrayList<>();
    }

    /**
     * 解析表达式
     *
     * @param expression
     * @param list
     */
    private static void parseExpression(Expression expression, List<FilterSetting> list) {
        if (expression instanceof AndExpression andExpression) {
            parseExpression(andExpression.getLeftExpression(), list);
            parseExpression(andExpression.getRightExpression(), list);
        } else if (expression instanceof OrExpression orExpression) {
            parseExpression(orExpression.getLeftExpression(), list);
            parseExpression(orExpression.getRightExpression(), list);
        } else if (expression instanceof GreaterThan greaterThan) {
            list.add(new FilterSetting().setFieldName(greaterThan.getLeftExpression().toString()).setCondition("gt"));
        } else if (expression instanceof LikeExpression likeExpression) {
            list.add(new FilterSetting().setFieldName(likeExpression.getLeftExpression().toString()).setCustomTableConfigId("like"));
        } else if (expression instanceof EqualsTo equalsExpression) {
            list.add(new FilterSetting().setFieldName(equalsExpression.getLeftExpression().toString()).setCustomTableConfigId("eq"));
        } else if (expression instanceof MinorThan minorThan) {
            list.add(new FilterSetting().setFieldName(minorThan.getLeftExpression().toString()).setCondition("lt"));
        } else {
            log.warn("Unknown Expression: " + expression);
        }
    }

    @Override
    public void saveConfig(CustomTableConfigDetailVO customTableConfig) {
        if (S.isNotBlank(customTableConfig.getId())) {
            CustomTableConfigDetailVO viewObject = this.getViewObject(customTableConfig.getId(), CustomTableConfigDetailVO.class);
            List<FilterSettingListVO> filterSettings = viewObject.getFilterSettings();
            List<CustomTableItemConfigListVO> tableItemConfigs = viewObject.getTableItemConfigs();
            List<CustomTableItemConfigListVO> tableItemConfigsSubmit = customTableConfig.getTableItemConfigs();
            List<FilterSettingListVO> filterSettingsSubmit = customTableConfig.getFilterSettings();
            // 删除已删除的过滤设置
            if (filterSettings != null) {
                List<String> deleteFilterSetting = filterSettings.stream().filter(e -> filterSettingsSubmit.stream().noneMatch(item -> item.getId().equals(e.getId()))).map(FilterSetting::getId).toList();
                filterSettingService.deleteEntities(deleteFilterSetting);
            }
            // 删除已删除的字段
            if (tableItemConfigs != null) {
                List<String> deleteTableItemConfig = tableItemConfigs.stream().filter(e -> tableItemConfigsSubmit.stream().noneMatch(item -> S.equals(e.getId(), item.getId()))).map(CustomTableItemConfig::getId).toList();
                customTableItemConfigService.deleteEntities(deleteTableItemConfig);
            }
        }
        this.createOrUpdateEntity(customTableConfig);
        List<CustomTableItemConfigListVO> tableItemConfigs = customTableConfig.getTableItemConfigs();
        if (tableItemConfigs != null) {
            tableItemConfigs.forEach(e -> e.setCustomTableConfigId(customTableConfig.getId()));
        }
        List<FilterSettingListVO> filterSettings = customTableConfig.getFilterSettings();
        if (filterSettings != null) {
            filterSettings.forEach(e -> e.setCustomTableConfigId(customTableConfig.getId()));
        }
        customTableItemConfigService.createOrUpdateEntities(tableItemConfigs);
        filterSettingService.createOrUpdateEntities(filterSettings);
    }


    @Override
    public List<LabelValue> findEntityList() {
        List<String> packageNames = List.of("com.hzncc.flowable_diboot.entity", "com.hzncc.flowable_diboot.contract.entity",
                "com.hzncc.flowable_diboot.project_contracts.entity", "com.hzncc.flowable_diboot.payment.entity");
        List<LabelValue> entityList = new ArrayList<>();
        for (String packageName : packageNames) {
            Reflections reflections = new Reflections(new ConfigurationBuilder()
                    .forPackages(packageName)
                    .addScanners(Scanners.TypesAnnotated));

            reflections.getTypesAnnotatedWith(TableName.class).forEach(e -> {
                log.info(e.getName());
                entityList.add(new LabelValue(e.getSimpleName(), e.getName()));
            });

        }
        return entityList;
    }

    @Override
    protected void afterDelete(Object entityIds) {
        log.info("删除自定义表格配置{}", entityIds);
        if (entityIds instanceof String) {
            customTableItemConfigService.deleteEntities(customTableItemConfigService.lambdaQuery().eq(CustomTableItemConfig::getCustomTableConfigId, entityIds));
            filterSettingService.deleteEntities(filterSettingService.lambdaQuery().eq(FilterSetting::getCustomTableConfigId, entityIds));
        } else if (entityIds instanceof Collection ids) {
            customTableItemConfigService.deleteEntities(customTableItemConfigService.lambdaQuery().in(CustomTableItemConfig::getCustomTableConfigId, ids));
            filterSettingService.deleteEntities(filterSettingService.lambdaQuery().in(FilterSetting::getCustomTableConfigId, ids));
        }
        super.afterDelete(entityIds);
    }


    /**
     * 根据编码获取配置
     *
     * @param code
     * @return
     */
    @Override
    public CustomTableConfigDetailVO getConfig(String code) {
        CustomTableConfig singleEntity = this.getSingleEntity(new QueryWrapper<CustomTableConfig>().lambda().eq(CustomTableConfig::getCode, code));
        CustomTableConfigDetailVO config = Binder.convertAndBindRelations(singleEntity, CustomTableConfigDetailVO.class);
        QueryWrapper<TableFieldShowConfig> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TableFieldShowConfig::getCustomTableConfigId, config.getId())
                .eq(TableFieldShowConfig::getUserId, IamSecurityUtils.getCurrentUserId());
        TableFieldShowConfig tableFieldConfig = tableFieldShowConfigMapper.selectOne(queryWrapper);
        if (tableFieldConfig != null) {
            TableFieldShowConfigDetailVO tableFieldShowConfigDetailVO = Binder.convertAndBindRelations(tableFieldConfig, TableFieldShowConfigDetailVO.class);
            List<TableFieldShowItem> fieldItems = tableFieldShowConfigDetailVO.getFieldItems();
            // 将config中的字段配置替换为用户自己的个性化配置
            if (fieldItems != null) {
                List<CustomTableItemConfigListVO> tableItemConfigs = config.getTableItemConfigs();
                Map<String, TableFieldShowItem> map = fieldItems.stream().collect(Collectors.toMap(TableFieldShowItem::getFieldName, Function.identity()));
                for (CustomTableItemConfigListVO tableItemConfig : tableItemConfigs) {
                    TableFieldShowItem fieldItem = map.get(tableItemConfig.getFieldName());
                    if (fieldItem.getFieldName().equals(tableItemConfig.getFieldName())) {
                        tableItemConfig.setViewable(fieldItem.getViewable());
                        tableItemConfig.setExportable(fieldItem.getExportable());
                        tableItemConfig.setWidth(fieldItem.getWidth());
                        tableItemConfig.setFieldLabel(fieldItem.getFieldLabel());
                    }
                }
            }
        }
        return config;
    }

    @Override
    protected void afterCreate(CustomTableConfig entity) {
        if (S.isBlank(entity.getQueryInterface())) {
            entity.setQueryInterface("/custom-table/common-select");
        }
        if (S.isBlank(entity.getExportInterface())) {
            entity.setExportInterface("/custom-table/common-export");
        }
        this.updateEntity(entity);
        super.afterCreate(entity);
    }

    @Override
    public void copyToTenant(List<String> codes, String tenantId) {
        List<CustomTableConfig> configs = this.lambdaQuery().in(CustomTableConfig::getCode, codes).list();
        List<CustomTableConfigDetailVO> customTableConfigDetailVOS = Binder.convertAndBindRelations(configs, CustomTableConfigDetailVO.class);
        for (CustomTableConfigDetailVO detail : customTableConfigDetailVOS) {
            detail.setTenantId(tenantId);
            detail.setId(null);
            detail.setCreateTime(null);
            this.createEntity(detail);
            if (detail.getFilterSettings() != null)
                detail.getFilterSettings().forEach(e -> {
                    e.setCustomTableConfigId(detail.getId());
                    e.setId(null);
                    e.setTenantId(tenantId);
                    e.setCreateTime(null);
                });
            if (detail.getTableItemConfigs() != null)
                detail.getTableItemConfigs().forEach(e -> {
                    e.setId(null);
                    e.setCustomTableConfigId(detail.getId());
                    e.setTenantId(tenantId);
                    e.setCreateTime(null);
                });
            filterSettingService.createEntities(detail.getFilterSettings());
            customTableItemConfigService.createEntities(detail.getTableItemConfigs());
        }
    }
}